#!/usr/bin/env python
#coding=utf-8
'''
Created on Aug 19, 2010
@author: lxd
'''
import types
import pyamf
from pyamf.remoting.client import RemotingService
from pyamf.remoting import RemotingError

import parse
import config

import time
import threading
p_lock = threading.RLock()#for post
def post_lock(fun):
    def _(*args, **kargs):
        p_lock.acquire()
        result = fun(*args, **kargs)
        p_lock.release()
        return result
    return _
s_lock = threading.RLock()#for time.sleep
        
class ClientError(Exception):pass

class Client():      
    def __init__(self, log, cookies, serverId): 
        self.log = log   
        self.client = self.getAMFClient(cookies, serverId)
        
    def getAMFClient(self, cookies, serverId):
        gateway = 'http://s%s.jn2.7.qq.com/dynasty/messagebroker/amf' % serverId
        referer = 'http://cdn.dl.7.qq.com/dynasty/swf/Loading.swf?7b7df3a0b1466fdd47005e9cbce61cde'
                
        pyamf.remoting.CONTENT_TYPE = 'application/x-amf;charset=UTF-8'
        user_agent = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3) Gecko/20100423 Ubuntu/10.04 (lucid) Firefox/3.6.3'

        client = RemotingService(gateway, amf_version=pyamf.AMF3, logger=self.log, user_agent=user_agent, referer=referer)
        client.http_headers = {
                            'cookie':cookies,
                            'Connection':'keep-alive', #not need indeed
                            'Keep-Alive':115,
                            'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                            'Accept-Language':'en-us,en;q=0.5',
                            'Accept-Encoding':'gzip,deflate',
                            'Accept-Charset':'x-gbk,utf-8;q=0.7,*;q=0.7',
                             }
        return client
    
    @post_lock 
    def postData(self, serviceName, funName, *args):
        def amfData(lst):
            from pyamf.amf3 import ByteArray
            data = ByteArray()
            if isinstance(lst, types.ListType):
                for l in lst:        
                    data.writeUnsignedByte(l)
            return data
        
        def encode(value):
            '''
            >>> value = 40777
            >>> encode(value) 
            [48, 130, 190, 125]
            '''        
            from pyamf import amf3
            b = amf3.ByteArray()
            key = "4784e4708d99d915d39ddf933497bbad"
            noise = 3
            
            b.writeObject(value)
            data = b.getvalue()
        #    print '原始数据%s' % repr(data)
        #    print '加密前数据%s' % [ord(i) for i in data]
            
            r = []
            for i in range(len(data)):
                if i % noise == 0:
                    loc8 = i % len(key)
                    r.append(ord(data[i]) ^ int(ord(key[loc8])))
                else:
                    r.append(ord(data[i])) 
            return r          
        
        result = None
        service = self.client.getService(serviceName)
        if args:
            data = []
            for arg in args:    
                data.append(amfData(encode(arg)))
            try:
                result = getattr(service, funName)(*data) 
            except RemotingError, err:
                self.log.error((RemotingError, err))
                raise
        else:
            try:
                result = getattr(service, funName)() 
            except RemotingError, err:
                self.log.error((RemotingError, err))
                raise
        return result 

    def __my_sleep(self, seconds):   
        s_lock.acquire()
        time.sleep(seconds)
        s_lock.release()    
         
    def wait(self, seconds):
        last_time = time.time()
        last_seconds = 0
        while last_seconds < seconds:
            self.receiveAllMessage()
            self.__my_sleep(3)
            last_seconds = time.time() - last_time
    
    def receiveAllMessage(self):
        self.postData('chatAct', 'receiveAllMessage', '1')
            
    def getCryptKey(self):
        data = self.postData('accountAct', 'getCryptKey')
        key = data['key']
        num = data['num']
        self.log.info('key:%s;num:%s' % (key, num))
        
    def isEnterGame(self):
        if self.postData('accountAct', 'isEnterGame') == 0:
            self.log.info('enter game success')
        else:
            self.log.error('enter game failure')
            raise ClientError('isEnterGame is not 0')
        
    def enterGame(self):        
        data = self.postData('accountAct', 'enterGame')
        return parse.enterGame(data) 
    
    def getUserCastles(self):   
        data = self.postData('accountAct', 'getUserCastles')
        return parse.getUserCastles(data)

    def getUserDailyMissionList(self):   
        return self.postData('dailyMissionAct', 'getUserDailyMissionList')

    def listCastleBuilding(self, casId):        
        data = self.postData('castleAct', 'listCastleBuilding', casId)
        return parse.listCastleBuilding(data)
    
    def getEndTime(self, mission_id):
        data = self.postData('dailyMissionAct', 'getEndTime', mission_id)
        return parse.getEndTime(data)
    
    def actDailyMission(self, mission_id, casId):    
        return self.postData('dailyMissionAct', 'actDailyMission', mission_id, casId)
        
    def levelUpCastleBui(self, casBuiId):    
        self.postData('castleAct', 'levelUpCastleBui', casBuiId)
        
    def refreshCasBui(self, casId, posNo):
        data = self.postData('castleAct', 'refreshCasBui', casId, posNo)  
        return parse.refreshCasBui(data).isBuilding
    

